@date/holidays
![Coverage Status](https://coveralls.io/repos/github/elidoran/node-date-holidays/badge.svg?branch=master)
Store and compare holiday dates.
Install
npm install @date/holidays --save
Usage: Add Simple Holiday
Some holidays are always on the same date so are easy to calculate.
var Holidays = require('@date/holidays')
var holidays = Holidays()
holidays.add({
info: {
name: 'Valentine\'s Day'
public: true
},
date: {
month: 1
day : 14
}
})
Usage: Add Complicated Holiday
Some holidays require calculating when they occur, and, whether they have an "observed" date as well.
Do all the work in the generator function.
holidays.add(function (year) {
var mainDate = new Date(year, 6, 4)
var holiday = {
info: {
name: 'Independence Day',
public: true
},
date: {
month: mainDate.getMonth(),
day : mainDate.getDate()
}
}
var day = mainDate.getDay()
var observed = 0
if (day === 0) observed = 1
else if (day === 6) observed = -1
else holiday.info.bank = true
if (observed !== 0) {
return [
holiday,
{
info: {
name: 'Independence Day (Observed)',
public: true,
bank: true,
observed: true
},
date: {
month: 6,
day : 4 + observed
}
}
]
}
else {
return holiday
}
})
Usage: Helpers
Use @date/generator
and @date/business
to help create the functions which calculate the dates.
var gen = require('@date/generator')
var biz = require('@date/business')()
var info = {
name: 'President\'s Day',
bank: true,
public: true
}
holidays.add(function (year) {
var date = gen.third().monday().in().february().of(year)
return {
info: info,
date: {
month: date.getMonth(),
day : date.getDate()
}
}
})
mainInfo = {
name : 'New Year\'s Day',
bank : true,
public: true
}
observedInfo = {
name : 'New Year\'s Day (Observed)',
bank : true,
public : true,
observed: true
}
holidays.add(function (year) {
var date = new Date(year, 0, 1)
var holiday = {
info: info,
date: {
month: date.getMonth()
day : date.getDate()
}
}
switch (date.getDay()) {
case 0:
biz.nextBusinessDay(date)
break
case 6:
biz.previousBusinessDay(date)
break
default:
return holiday
}
return [
holiday,
{
info: observedInfo,
date: {
month: date.getMonth(),
day : date.getDate()
}
}
]
})
API
API: add()
Adds a holiday to the holidays
instance.
There are two ways to add a holiday, one for a simple fixed date holiday and one for a holiday which requires calculating its date.
For a simple fixed date you can specify an object with the info
and date
properties and the add()
function will create the generator function. It will return that function so it can be stored and used with the remove()
function to remove it.
For a calculated date, specify a function which accepts a single argument, the year, and returns an object containing the info
and the date
of the holiday, or, an array of those objects for multiple holidays.
It's acceptable to calculate many holidays in one generator function and return them all in an array. See the @date/holidays-us for an example.
The info
is used in two places:
- as the return value of
getHoliday()
- for comparison of extra properties given to
isHoliday()
and getHoliday()
as "filters"
holidays.add(function (year) {
return {
info: {
name: 'Holiday Name'
public: true
bank : true
},
date: {
month: 0,
day : 1
}
}
return [
]
})
API: remove()
Remove a holiday generator.
Specify a previously added generator function and it will be removed.
Note, any holidays already generated by the generator will still be in the cache. You must purge them if they are no longer wanted.
Note, when adding a fixed date using an object, instead of a function, the function created is returned from add()
as the key to use for remove()
.
fn = someGeneratorFunction()
holidays.add(fn)
holidays.remove(fn)
fn = holidays.add({
info: { },
date: { month: 3, day: 9 }
})
holidays.remove(fn)
API: isHoliday()
Returns false unless it is aware of a holiday on the specified date.
Note, all holiday generators will be called to create holidays for the year of the specified Date
argument.
Extra criteria can be specified and the holiday's info
will be tested for those values. All specified values must exist in the info
for it to return true.
For example, to check if a holiday is a bank holiday do:
var date = getSomeDate()
holidays.isHoliday(date, { bank: true })
holidays.isHoliday({ date: date, bank: true })
holidays.isHoliday({ bank: true }, date)
API: getHoliday()
Retrieve the holiday's info
set into the holidays
instance.
var specifiedInfo = {
name: 'New Year\'s Day',
public: true
}
holidays.add({
info: specifiedInfo,
date: {
month: 0,
day : 1
}
})
var date = new Date(2016, 0, 1)
var returnedInfo = holidays.getHoliday(date)
returnedInfo = holidays.getHoliday(date, { public: true })
returnedInfo = holidays.getHoliday(date, { bank: true })
API: purge functions
The holidays
instance caches calculated holidays by year. The purge functions help remove cached holiday info.
When using the purge functions it nulls the value and leaves the year property in the cache. Over time this will build up keys without a value. (As opposed to using delete
on the keys which is undesirable.)
One exception is the purge()
function. It creates a brand new cache object with no properties.
The purge functions:
purge()
- replaces cache with a new empty onepurgeYear()
- accepts one argument, a number, and nullifies that year's holidayspurgeYears()
- accepts multiple arguments, either a number or an array of numbers, and nullifies each year's holidayspurgeYearRange()
- accepts two arguments, both numbers, as the from/to range (inclusive) to purge
holidays.purge()
holidays.purgeYear(2016)
holidays.purgeYears(2005, 2012, 2013)
holidays.purgeYears([2001, 2004, 2008])
holidays.purgeYearRange(1999, 2018)
Why not do all that in purge() ?
Originally I was, but, I changed my mind because:
- the function was then more complicated than necessary
- it's better to make functions more focused
- if performance were important on these functions, accepting different types of arguments would reduce its performance
- and, best of all, it's more readable this way
API: compact()
The holidays
instance caches calculated holidays by year. When using the purge functions it nulls the value and leaves the year property in the cache. Over time this will build up keys without a value.
Calling compact()
will replace the current cache with a new one containing only those years with defined values; eliminating those with null values.
holidays.isHoliday(2001)
holidays.purgeYear(2001)
holidays.compact()